"""
WSGI Middleware to create a APP client for blogging.
"""
from selector import *
from paste.request import parse_formvars
from brightcontent.plugins.staticfiles import StaticFiles
from brightcontent.core import SLUGCHARS
from brightcontent.core.store import COMMON_PREFIXES
from brightcontent.util import get_base_url, fixup_characters
from Ft.Xml.Xslt import Transform
from Ft.Xml import Domlette, Parse
from Ft.Lib import Uri
import re, os, amara, dateutil, posixpath
from mimetypes import guess_type
from string import Template
from wsgixml.applyxslt import setup_xslt_params
from pprint import pprint
import httplib2
from pkg_resources import resource_string

AC_NS = u"http://brightcontent.net/ns/app-client"
XHTML_NS = u"http://www.w3.org/1999/xhtml"

class AppService(object):

    def __init__(self, service=None):
        if service:
            self.get(service)

    def get(self, url):
        self.doc = amara.parse(url)


class AppClient(object):
    def __init__(self, collection_url):
        self.h = httplib2.Http('.cache')
        self.collection = collection_url

    def put_entry(self, entry_xml):
        pass

    def post_entry(self, entry_xml, data={}):
        headers = {'Content-type' : 'application/atom+xml;type=entry'}
        if data.get('atom_slug', None):
            headers['slug'] = data['atom_slug']
        print headers
        print entry_xml.xml(indent=True)
        print 'Posting to: %s' % self.collection
        resp, content = self.h.request(self.collection, "POST",
                    body=entry_xml.xml(inden=True), headers=headers)
        return (resp, content)

    def get_entry(self, entry_url):
        pass

    def delete_entry(self, entry_url):
        pass


class AppClientRenderer(object):

    def __init__(self):
        self.rs = '%s.xslt'

    def get(self, f):
        return resource_string(__name__, 'atomprotocolclient/%s' % f)

    def render(self, xml, xslt, params={}, errors={}):
        params['check_params'] = "Yup they are working!"
        if len(errors):
            for k, v in errors.items():
                params['err_%s' % k] = v
        xslt = self.get(xslt)
        xml = self.get(xml)
        nodes = {}
        for k, v in params.items():
            if isinstance(v, list):
                nodes[k] = v
        params = setup_xslt_params(AC_NS, params)
        for k, v in nodes.items():
            params[(AC_NS, k)] = v
        return Transform(xml, xslt, params=params)

class AppClientMiddleware(object):

    def __init__(self, app=None):
        self.view = AppClientRenderer()
        self.client = AppClient('http://localhost:8080/blog/')
        self.collections = []
        # self.client = AppClient('http://ionrock.org/blog/')
        self.s = Selector()
        self.s.add('/create', GET=self.create, POST=self.create)
        self.s.add('/static/{js:any}', GET=self.static)
        self.s.add('/', GET=self.index, POST=self.add_service)

    def __call__(self, environ, start_response):
        print "in call"
        return self.s(environ, start_response)

    def render(self, action, data, errors):
        print 'in render'
        xml = '%s/source.xml' % action
        xslt = '%s/forms.xslt' % action
        return self.view.render(xml, xslt, data, errors)

    def index(self, environ, start_response, data={}, errors={}):
        data['base_url'] = get_base_url(environ)
        output = self.render('index', data, errors)
        start_response('200 OK', [('content-type', 'text/html')])
        return [output]

    def add_collection(self, cdoc):
        if cdoc.href not in [ x[0] for x in self.collections ]:
            self.collections.append((cdoc.href, cdoc.title))
    
    def add_service(self, environ, start_response):
        print "in add_service"
        post = parse_formvars(environ)
        pprint(post)
        if post.get('app_service', ''):
            doc = amara.parse(post['app_service'])
            data = {'service' : [doc]}
            return self.index(environ, start_response, data)
        return self.index(environ, start_response)
    
    def create(self, environ, start_response):
        print "in create"
        data = {}
        errors = {'atom_title' : '*',
                  'atom_content' : '*'}
        data['base_url'] = get_base_url(environ)
        if environ['REQUEST_METHOD'] == 'POST':
            atom_entry = ClientAtomEntry(environ)
            if atom_entry.invalid:
                errors = atom_entry.invalid
                for k, v in parse_formvars(environ).items():
                    data[k] = v
            else:
                headers, body = self.client.post_entry(atom_entry.entry_xml, atom_entry.data)
                print headers
                if headers.get('status', '') == '201':
                    print 'Created!'
                    data['location'] = headers['location']
                else:
                    print 'Status: %s' % headers['status']
                    for k, v in parse_formvars(environ).items():
                        data[k] = v
        output = self.render('create', data, errors)
        start_response('200 OK', [('content-type', 'text/html')])
        return [output]

    def update(self, environ, start_response):
        pass

    def edit(self, environ, start_response):
        pass

    def static(self, environ, start_response):
        fn = environ['wsgiorg.routing_args'][1]['js']
        # from pprint import pprint
        # pprint(environ)
        fn = posixpath.join('atomprotocolclient/static', fn)
        print "Trying to get: %s" % fn
        try:
            # fn = file(self.sf.fget(fn), 'rb').read()
            fn = resource_string(__name__, fn)
            start_response('200 OK', [('content-type', guess_type(fn))])
            return [fn]
        except IOError, e:
            start_response('404 Not Found', [('content-type', 'text/plain')])
            error = '"%s" not found' % fn
            return [error,]

class ClientAtomEntry(object):
    def __init__(self, environ):
        self.env = environ
        post = parse_formvars(environ)
        self.data = {}
        for k, v in post.items():
            if '${atom_' not in v:
                self.data[k] = v
        self.entry_xml = self.create(self.data)
        self.invalid = self.valid(self.entry_xml)

    def create(self, data):
        xml = resource_string(__name__, 'atomprotocolclient/create/source.xml')
        xslt = resource_string(__name__, 'atomprotocolclient/create/template.xslt')
        #wrap xhtml types
        xhtml = amara.create_document(u'div', ns=XHTML_NS)
        d = fixup_characters(data['atom_content'])
        xhtml.div.xml_append_fragment(d)
        data['atom_content'] = xhtml.div
        # data['atom_summary'] = entity2num(data['atom_summary'])
        output = Transform(xml, xslt, params=setup_xslt_params(AC_NS, data))
        doc = amara.parse(output, prefixes=COMMON_PREFIXES)
        doc.entry.content.xml_append(data['atom_content'])
        # doc.entry.summary.xml_append_fragment(data['atom_summary'])
        return doc
        
    def valid(self, doc=None):
        if not doc:
            doc = self.entry_xml
        errors = {}
        if hasattr(doc.entry, 'title'):
            if not str(doc.entry.title).strip():
                errors['atom_title'] = '*'

        if hasattr(doc.entry, 'author'):
            if not str(doc.entry.author.name):
                errors['atom_author'] = '*'

        if hasattr(doc.entry, 'content'):
            if not str(doc.entry.content).strip():
                errors['atom_content'] = '*'

        return errors
            

def parse_id(url):
    """
    Function to be overridden or used as-is for parseing the 'id' of
    the url. For example, the default is:

      {id} == {year}/{month}/{day}/{slug}.atom

    Simply return the value as needed after parsing the arguments. For
    example, the default case might simply parse:

      /2007/3/4/My_Slug -> /2007/03/04/My_Slug.atom

    The simple goal here is to return some string value that can be
    queried in some sort of APP store.
    """
    regex = re.compile(r'/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>[%s]+)'%(SLUGCHARS))
    query_dict = regex.match(url).groupdict()
    if query_dict:
        year = query_dict('year', None)
        month = query_dict('month', None)
        day = query_dict('day', None)
        year, month, day = int(year), int(month), int(day)
        slug = query_dict('slug', None)
        if year and month and day and slug:
            entry_date = datetime(year, month, day, 0, 0, 0)
            if not slug.endswith('.atom'):
                slug = slug.rstrip('/') + '.atom'
            return posixpath.join(entry_date.strftime('/%Y/%m/%d'), slug)
    return False

